package com.apache.passport.common;

import java.io.File;
import java.io.IOException;
import java.util.*;

import javax.servlet.*;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.apache.database.constant.Validator;

import com.apache.database.constant.SystemTools;
import com.apache.license.filter.AbstractFilter;
import com.apache.passport.entity.Token;
import com.apache.security.util.SecurityHttpServletRequest;
import com.apache.security.util.SecurityHttpServletResponse;
import com.apache.tools.ConfigUtil;
import com.apache.tools.StrUtil;
import com.apache.uct.common.ToolsUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * description: Sso服务统一过滤器
 *
 * @author dyh 创建时间：2018年01月29日
 */
public class SsoServerFilter extends AbstractFilter {

	private Logger log = LoggerFactory.getLogger(SsoServerFilter.class);

	private static final String SUFFIX = "js,css,png,jpg,gif,bmp,swf,fla,ico";

	private String COOKIENAME = "";

	//自定义登录页面
	private String login_url = "";

	private String consoleUser = "";

	//白名单
	private String white_url = "";

	//访问未授权地址,跳转url
	private String jumpUrl = "";

	private boolean isOpenSecurityFilter = false;//是否开启安全过滤

	// rpc服务地址,引入此属性,主要是因为加密统一
	private String rpc_service_url = "";

	private Map<String, String> unLockMap = new HashMap<String, String>();

	private Map<String, ArrayList<String>> whiteMap = new HashMap<String, ArrayList<String>>();

	///监控请求白名单
	private List<String> whiteJK= new ArrayList<String>() {{
		add("/health");
		add("/info");
		add("/auditevents");
		add("/metrics");
		add("/logfile");
		add("/loggers");
		add("/jolokia");
		add("/flyway");
		add("/liquibase");
		add("/dump");
		add("/heapdump");
		add("/auditevents");
		add("/env");
		add("/turbine");
		add("/trace");
		add("/hystrix");
		add("/api");
		add("/refresh");
		add("/offline");
		add("/online");
		add("/refresh");
	}};

	@Override
	public void init(FilterConfig filterConfig) throws ServletException {
		this.initLincense();
		//初始化uct服务端 白名单配置
		unLockMap.put("/login.jsp", "");
		unLockMap.put("/login_jwt.jsp", "");
		unLockMap.put("/login.html", "");
		unLockMap.put("/login_jwt.html", "");
		initValue();
		try {
			String xmlStr = ConversionModelFactory.getInstance().readModelXMl();
			if(Validator.isNotNull(xmlStr)){
				SsoConversionModel model = JaxbUtil.xmlToBean(xmlStr, SsoConversionModel.class);
				ConversionModelFactory.getInstance().setModel(model);
			}
		} catch (Exception e){
			e.printStackTrace();
			log.error("加载转换模型配置失败");
		}
	}

	private void initValue() {
 		COOKIENAME = SystemTools.getInstance().getValue("cookieName");
		//自定义登录页面
		login_url = SystemTools.getInstance().getValue("login.url");
		//白名单
		white_url = SystemTools.getInstance().getValue("white.url");
		//访问未授权地址,跳转url
		jumpUrl = SystemTools.getInstance().getValue("jump.url");
		rpc_service_url = SystemTools.getInstance().getValue("rpc_service_url");
		String isFilter = StrUtil.doNull(SystemTools.getInstance().getValue("is_open_security_filter"), "false");
		isOpenSecurityFilter = Boolean.parseBoolean(isFilter);
		this.consoleUser = SystemTools.getInstance().getValue("uct_supper_user");
	}

	@Override
	public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
			throws IOException, ServletException {

		HttpServletRequest req = (HttpServletRequest) servletRequest;
		HttpServletResponse resp = (HttpServletResponse) servletResponse;
		resp.setCharacterEncoding("UTF-8");
		resp.setDateHeader("expires", 0);
		resp.setHeader("Cache-Control", "no-cache");
		resp.setHeader("pragma", "no-cache");
		//CookeHeader(resp, req);
		//判断是否为外部系统登录
		String sysEname = req.getParameter("sys");
		String setCookieUrl = req.getParameter("cset");
		String goUrl = req.getParameter("go");
		String clientId = req.getParameter("_client");
		String ptlang = req.getParameter("ptlang");

		//获取uri信息
		String uri = req.getRequestURI();
		//获取访问路径
		String servletPath = req.getServletPath();
		//获取后缀名
		String suffix = PassportHelper.getInstance().parseUrlSuffix(uri);
		//后缀名小写
		suffix = suffix.toLowerCase();

		//如果存在后缀为图片,css等格式,直接跳过,不拦截
		if (StrUtil.isNotNull(suffix)) {
			if (SUFFIX.contains(suffix)) {
				filterChain.doFilter(servletRequest, servletResponse);
				return;
			}
		}

		//监控白名单处理
		if(jkWhite(servletPath)){
			filterChain.doFilter(servletRequest, servletResponse);
			return;
		}

		//获取token
		String tokenCookie = PassportHelper.getInstance().getCurrCookie(req);
		//获取ucsso
		String ucsso = StrUtil.doNull(PassportHelper.getInstance().getCurrCookie(req, "_uc.sso"),req.getHeader("zuulucsso"));;

		if (ConfigUtil.getInstance().checkFileUpdate("")||StrUtil.isNull(white_url)) {
			initValue();
		}
		//2015年2月4日11:07:24 更新 如果客户端根据token访问获取,如果不存在值,则从request中取值
		String pkt = req.getParameter("tokenId");
		if (!StrUtil.isNull(pkt)) {//第三方系统或客户端
			outwardSys(goUrl, pkt, setCookieUrl, ptlang, req, resp);
			return;
		}
		Token token = PassPortConst.getToken(tokenCookie);
		//(Token) SystemTools.getInstance().getCache("loginToken").getCacheCloneByKey(tokenCookie);
		req.getSession().setAttribute("ctx", req.getContextPath());
		if (ToolsUtil.isEmpty(token)) {//白名单处理
			if (actPathGoto(req)) {
				gotoPage(req, resp, filterChain);
				return;
			}
		} else {
			if ((!ToolsUtil.isNull(sysEname) && !ToolsUtil.isNull(setCookieUrl) && !ToolsUtil.isNull(goUrl)
					&& !ToolsUtil.isNull(clientId))) {
				//获取tokenId,然后跳进连入地址
				req.setAttribute("tokenId", token.getTokenId());
				resp.sendRedirect(setCookieUrl + "?ticket=" + token.getTokenId() + "&go=" + goUrl + "&ucsso=" + ucsso);
				return;
			} else {
				String desEname = token.getUserEname();
				if (!StrUtil.isNull(desEname)) {
					req.setAttribute("ctx",req.getContextPath());
					String gtype = req.getHeader("gateway-type");
					desEname = DesUtils.getInstance().decrypt(desEname);
					if (consoleUser.indexOf(desEname) > -1) {
						if("/".equals(servletPath) || servletPath.indexOf("/login.") > -1){
						} else {
							gotoPage(req, resp, filterChain);
							return ;
						}
					}
					if(StrUtil.isNull(gtype)) {
						resp.sendRedirect(req.getContextPath() + this.jumpUrl);
					} else {
						req.getRequestDispatcher(this.jumpUrl).forward(req, resp);
					}
					return;
				}
			}
		}
		//如果不存在.则跳转其他页面,默认为登录页面
		String secret_key_type = ToolsUtil.getInstance().getValueByKey("secret_key_type");
		if ("rsa".equalsIgnoreCase(secret_key_type)) {
			resp.sendRedirect(login_url + "/login_jwt.html");
		} else {
			resp.sendRedirect(login_url + "/login.html");
		}
	}

	private void gotoPage(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
			throws IOException, ServletException {
		if ("true".equalsIgnoreCase(ToolsUtil.getInstance().getValueByKey("is_open_security_filter"))) {//是否开启安全过滤
			filterChain.doFilter(new SecurityHttpServletRequest(request), new SecurityHttpServletResponse(response));
		} else {
			filterChain.doFilter(request, response);
		}
	}

	private boolean actPathGoto(HttpServletRequest request) {
		String servletPath = request.getServletPath();
		Iterator<String> it = unLockMap.keySet().iterator();
		while (it.hasNext()) {
			String url = it.next();
			if (servletPath.indexOf(url) > -1) {
				return true;
			}
		}
		List<String> whites = Arrays.asList(white_url.split(","));
		if (whites.contains(servletPath)) {
			return true;
		}
		//白名单处理
		if (unlockPath(servletPath)) {
			return true;
		}
		return false;
	}

	/**
	 * description:  外部系统调用
	 */
	private void outwardSys(String goUrl, String pkt, String setCookieUrl, String ptlang, HttpServletRequest req,
			HttpServletResponse resp) throws IOException, ServletException {
		Token token = PassPortConst.getToken(pkt);
		//如果为空,则让其跳转到客户端系统进行登录
		if (ToolsUtil.isEmpty(token)) {
			resp.sendRedirect(ToolsUtil.isNull(goUrl) ? login_url : goUrl);
			return;
		}
		String userName = DesUtils.getInstance().decrypt(token.getUserEname());
		//只处理客户端请求,加此判断主要用于passport系统使用tokenId登录时,防止误入此方法
		if ((!ToolsUtil.isNull(pkt) && !ToolsUtil.isNull(goUrl))) {
			//ptlang
			ArrayList<String> lst = new ArrayList<String>();
			lst.add(rpc_service_url);
			lst.add(pkt);
			lst.add(setCookieUrl);
			lst.add(goUrl);
			lst.add("apache");
			Collections.sort(lst);
			StringBuffer sb = new StringBuffer();
			for (int i = 0; i < lst.size(); ++i) {
				sb.append(lst.get(i));
			}
			String ptlangSha1 = PassportHelper.getInstance().SHA1(sb.toString());
			log.debug("rpc_url msg:[{}]" + rpc_service_url);
			log.debug("pkt msg:[{}]" + pkt);
			log.debug("setCookieUrl msg:[{}]" + setCookieUrl);
			log.debug("goUrl msg:[{}]" + goUrl);
			log.debug("ptlangSha1=" + ptlangSha1 + "; ptlang=" + ptlang);

			if (ptlangSha1.equals(ptlang)) {
				Cookie ticket = new Cookie(COOKIENAME, pkt);
				ticket.setPath("/");
				ticket.setMaxAge(-1);
				resp.addCookie(ticket);
				Cookie ucss = new Cookie("_uc.sso", userName);
				ucss.setPath("/");
				ucss.setMaxAge(-1);
				resp.addCookie(ucss);
				req.setAttribute("tokenId", token.getTokenId());
				resp.sendRedirect(setCookieUrl + "/cset" + "?ticket=" + token.getTokenId() + "&go=" + goUrl + "&ucsso="
						+ userName);
			} else {
				log.debug("passport msg:[{}]=Keys Are Different");
				req.getRequestDispatcher(jumpUrl).forward(req, resp);
			}
			return;
		} else {
			Cookie ticket = new Cookie(COOKIENAME, pkt);
			ticket.setPath("/");
			ticket.setMaxAge(-1);
			resp.addCookie(ticket);

			Cookie ucss = new Cookie("_uc.sso", userName);
			ucss.setPath("/");
			ucss.setMaxAge(-1);
			resp.addCookie(ucss);
			req.setAttribute("tokenId", token.getTokenId());
		}
	}

	/**
	 * description:  白名单判断
	 */
	private boolean unlockPath(String path) {
		XmlWhiteUtils.getInstance().deWhiteXml(whiteMap, "sso");
		ArrayList<String> whiteUrl = whiteMap.get("whiteUrl");
		ArrayList<String> whiteParadigm = whiteMap.get("whiteParadigm");
		int wp = whiteParadigm.size();
		if (path.length() > 1) {
			if (whiteUrl.contains(path)) {
				return true;
			}
			for (int i = 0; i < wp; i++) {
				if ((whiteParadigm.get(i)).contains("*")) {
					String wdir = (whiteParadigm.get(i)).replace("*", "");
					int s = path.indexOf(wdir);
					if (s == 0) {
						return true;
					}
				} else if (!"".equals(whiteParadigm.get(i))) {
					int s = path.indexOf(whiteParadigm.get(i));
					if (s == 0) {
						return true;
					}
				}
			}
		}
		return false;
	}

	@Override
	public void destroy() {

	}

	private boolean jkWhite(String servletPath){
		List<String> whiteJK= PassportHelper.whiteJK;
		for (int i = 0; i < whiteJK.size(); i++) {
			String wurl = whiteJK.get(i);
			if (servletPath.startsWith(wurl)) {
				return true;
			}
		}
		return false;
	}
}
